package com.hh.service.impl;


import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hh.entity.domain.Message;
import com.hh.entity.domain.User;
import com.hh.entity.enums.MessageType;
import com.hh.mapper.MessageMapper;
import com.hh.service.MessageService;
import com.hh.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @author hanhui
 * @description 针对表【notification(通知表)】的数据库操作Service实现
 * @createDate 2025-07-26 10:35:55
 */
@Slf4j
@Service
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message>
        implements MessageService {
    @Resource
    private MessageMapper messageMapper;
    @Resource
    private UserService userService;
    @Resource
    private SimpMessagingTemplate messagingTemplate;

    /**
     * 保存消息并推送给指定用户
     */
    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void sendMessageToUser(Message message) {
        // 保存消息到数据库
        messageMapper.insert(message);

        try {
            // 推送消息给指定用户
            log.info("发送消息给用户 ID: {}", message.getUserId());
            messagingTemplate.convertAndSendToUser(
                    String.valueOf(message.getUserId()),
                    "/queue/notifications",
                    message
            );
        } catch (Exception e) {
            log.error("发送消息给用户失败: userId={}, error={}", message.getUserId(), e.getMessage());
            // 可以考虑保存为离线消息
            saveOfflineMessage(String.valueOf(message.getUserId()), message.getContent());
            // 重新抛出异常以触发事务回滚
            throw new RuntimeException("消息发送失败", e);

        }
    }


    /**
     * 发送系统消息给所有用户
     */
    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void sendSystemMessage(String content) {
        Message message = new Message();
        message.setContent(content);
        message.setType(MessageType.SYSTEM_NOTICE.getValue());
        try {
            messageMapper.insert(message);
            messagingTemplate.convertAndSend("/topic/system", message);
        } catch (MessagingException e) {
            log.error("发送消息给用户失败: userId={}, error={}", message.getUserId(), e.getMessage());
            saveOfflineMessage(null, message.getContent());
            // 重新抛出异常以触发事务回滚
            throw new RuntimeException("消息发送失败", e);
        }

    }

    /**
     * 获取用户的消息列表
     */
    @Override
    public List<Message> getUserMessages(String userId) {
        return messageMapper.selectByUserIdOrderByCreateTimeDesc(userId);
    }

    /**
     * 将消息标记为已读
     */
    @Override
    @Transactional
    public int markAsRead(Long messageId) {
        Message message = new Message();
        message.setIsRead(1);

        UpdateWrapper<Message> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", messageId);

        return messageMapper.update(message, updateWrapper);
    }

    /**
     * 获取未读消息数量
     */
    @Override
    public long getUnreadCount(String userId) {
        return messageMapper.countUnreadByUserId(userId);
    }

    @Override
    public void saveOfflineMessage(String userId, Object message) {
        Message offlineMessage = new Message();
        offlineMessage.setUserId(Long.valueOf(userId));
        offlineMessage.setContent((String) message);
        offlineMessage.setType(MessageType.SYSTEM_NOTICE.getValue());
        this.save(offlineMessage);
    }

    @Override
    public int readAll(HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        Long userId = loginUser.getId();
        UpdateWrapper<Message> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("userId", userId);
        Message message = new Message();
        message.setIsRead(1);
        return messageMapper.update(message, updateWrapper);
    }
}




